package EP.MetricasContenido;

import Controladores.ControladorOperaciones;
import EP.Web.Pagina;
import EP.Web.RelacionPaginas;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;

/**
* @class IDF
* @author Mauricio Alvarez.
* @date 12-Diciembre-2010.
* @brief Esta clase representa la clase IDF, correspondiente a una entidad principal (EP).
*/
public class IDF
{
    
    /**
     *  @var int id_pagina
     *  @brief identificador de la página en la BD.
    */
    private int id_pagina;
    /**
     *  @var String Termino
     *  @brief Termino correspondiente a la consulta Q={q1,q2,...,qn}.
    */
    private String Termino;
    /**
     *  @var private double ND
     *  @brief Cantidad de páginas que contiene la BD en ese momento (lote).
    */
    private double ND = 0;
    /**
     *  @var private double NDti
     *  @brief Cantidad de páginas que contienen el termino i.
    */    
    private double NDti = 0;
    /**
     *  @var private double IDF
     *  @brief Valor del IDF para el lote de páginas obtenidas de la BD.
    */
    private double IDF = 0;
    /**
     *  @var private double IDF_O
     *  @brief Valor del IDF (Okapi BM25) para el lote de páginas obtenidas de la BD.
    */
    private double IDF_O = 0;
    /**
     *  @var private ControladorOperaciones cop
     *  @brief Varible global de tipo clase ControladorOperaciones.
    */
    private ControladorOperaciones cop;



    /////////////////
    // CONSTRUCTOR
    /////////////////
    public IDF()
    {
        cop = new ControladorOperaciones();
    }



    //////////////////////////
    // Getter y Setter
    //////////////////////////


    public double getIDF() {
        return IDF;
    }

    public void setIDF(double IDF) {
        this.IDF = IDF;
    }

    public double getIDF_O() {
        return IDF_O;
    }

    public void setIDF_O(double IDF_O) {
        this.IDF_O = IDF_O;
    }

    public double getND() {
        return ND;
    }

    public void setND(double ND) {
        this.ND = ND;
    }

    public double getNDti() {
        return NDti;
    }

    public void setNDti(double NDti) {
        this.NDti = NDti;
    }

    public String getTermino() {
        return Termino;
    }

    public void setTermino(String Termino) {
        this.Termino = Termino;
    }

    public int getId_pagina() {
        return id_pagina;
    }

    public void setId_pagina(int id_pagina) {
        this.id_pagina = id_pagina;
    }



    //////////////////////////
    // OPERACIONES
    //////////////////////////

    /**
     * @brief Calcula el IDF de todas las páginas que se encuentran dentro de la
     * base de datos para un termino que se entrega por entrada. Esta entrada puede
     * se cualquier consulta del usuario o palabras de la ontología.
     * @param Topico, Stopwords, ListaPaginas, ListaRelacionPaginas, TopicoConsultado, OpcionContenido y Umbral
     * @return Map<String, List>
    */
    public Map<String, List> CalcularIDF(Map<String, Integer> Topico,
                                  Map<String, Integer> Stopwords,
                                  List<Pagina> ListaPaginas,
                                  List<RelacionPaginas> ListaRelacionPaginas,
                                  String TopicoConsultado,
                                  int OpcionContenido,
                                  double Umbral,
                                  int Ranking) throws FileNotFoundException, IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException
    {

        ////////////////////////////////////////////////////////////////////////
        //PASO 0: Segun la selección de OpcionContenido (1:BODY/2:SURROUND TEXT)
        //        se calcula el tf:
        ////////////////////////////////////////////////////////////////////////
        int id_pagina = 0;
        int id_relacion_pag;
        int pag_id_pagina;
        String texto_alrededor;
        String contenido;
        IDF idf;

        ////////////
        // BODY   //
        ////////////
        if (OpcionContenido == 1)
        {

            System.out.println("***************************************");
            System.out.println("**     CALCULO DE IDF (BODY)         **");
            System.out.println("***************************************");

            
            //Guarda los resultadosIDF para cada página:
            List<IDF> ResultadosIDF = new ArrayList();
            //Guarda las páginas con los resultados IDF:
            Map<String, List> IDFPaginas = new HashMap();
            //Se obtiene la cantidad de páginas (lote) del estudio:
            ND = ListaPaginas.size();

            ////////////////////////////////////////////////
            //PASO 1: Para cada termino del topico hacer:
            ////////////////////////////////////////////////
            Set conjuntoTopico = Topico.entrySet();
            Iterator it = conjuntoTopico.iterator();

            while(it.hasNext())
            {
                //Se obtiene una palabra de la consulta o topico:
                Map.Entry me = (Map.Entry)it.next();
                Termino = (String) me.getKey();

                //Se resetea el valor del IDF para el lote de páginas para cada
                //termino:
                NDti = 0;

                //Para cada página del Lote hacer:
                for (int i = 0; i < ListaPaginas.size(); i++)
                {
                    //Guarda el listado de terminos de la página:
                    List<String> ContenidoPagina = new ArrayList();

                    //Diccionario de terminos para la página:
                    Set<String> TerminosPagina = new HashSet();

                    //Se obtienen los datos de la página:
                    Pagina pagina = new Pagina();
                    pagina = ListaPaginas.get(i);
                    id_pagina = pagina.getId_pagina();
                    contenido = pagina.getContenido();

                    //Se obtienen los terminos correspondientes del contenido de las
                    //páginas:
                    if (contenido == null)
                    {
                        contenido = "null";
                    }

                    ContenidoPagina = cop.ObtenerPalabrasPagina(contenido, Stopwords);

                    if (ContenidoPagina.isEmpty() == true)
                    {
                        ContenidoPagina.add("null");
                    }

                    //Para cada termino se contabiliza las apariciones en el documento:
                    for (int j = 0; j < ContenidoPagina.size(); j++)
                    {
                        TerminosPagina.add(ContenidoPagina.get(j));
                    }

                    //Para cada termino del diccionario de la página hacer:
                    Iterator iter = TerminosPagina.iterator();
                    while (iter.hasNext())
                    {
                        String termino = (String) iter.next();

                        //Si el termino del tópico o de la consulta está en el diccionario
                        //de la página, entonces:
                        if (termino.compareToIgnoreCase(Termino) == 0)
                        {
                            NDti++;
                        }

                    }

                }//for paginas

                ////////////////////////////////////////////////////////////////
                //PASO 2: Se calcula el IDF del termino i de la consulta
                ////////////////////////////////////////////////////////////////

                //Se valida si NDti = 0, para que no se produzcan errores:
                if (NDti == 0){
                    NDti = 1;
                    IDF = Math.log10(ND/NDti);
                }else{
                    IDF = Math.log10(ND/NDti);
                }

                ////////////////////////////////////////////////////////////////////////
                //PASO 2: Se calcula el IDF (Okapi BM25) del termino i de la consulta
                ////////////////////////////////////////////////////////////////////////
                IDF_O = Math.log10((ND - NDti + 0.5)/(NDti + 0.5));

                //Si IDF_O < 0 se iguala el IDF_O a 0.
                if (IDF_O < 0)
                {
                   IDF_O = 0;
                }

                ////////////////////////////////////////////////////////////////
                //PASO 3: Se guarda el IDF del termino i de la consulta
                ////////////////////////////////////////////////////////////////
                idf = new IDF();
                idf.setId_pagina(id_pagina);
                idf.setTermino(Termino);
                idf.setND(ND);
                idf.setNDti(NDti);
                idf.setIDF(IDF);
                idf.setIDF_O(IDF_O);


                //BORRAR ESTOOOOO!!!:!::!:!:!:!:!:!:!:!:!:!:!!:::!:!::!:!:!

                System.out.println("------------------------------------");
                System.out.println("id_pagina: "+ id_pagina);
                System.out.println("termino: "+ Termino);
                System.out.println("ND: "+ ND);
                System.out.println("NDti: "+ NDti);
                System.out.println("IDF: "+ IDF);
                System.out.println("IDF_O: "+ IDF_O);
                System.out.println("++++++++++++++++++++++++++++++++++++");

                //BORRAR ESTOOOOO!!!:!::!:!:!:!:!:!:!:!:!:!:!!:::!:!::!:!:!


                ResultadosIDF.add(idf);
                IDFPaginas.put(Termino, ResultadosIDF);

            }//while Terminos de consulta (topico)

            return IDFPaginas;

        }//FIN IF BODY


        
        ////////////////////
        // SURROUND TEXT  //
        ////////////////////

        if (OpcionContenido == 2)
        {
            System.out.println("***************************************");
            System.out.println("**  CALCULO DE IDF (SURROUND TEXT)   **");
            System.out.println("***************************************");


            //Guarda los resultadosIDF para cada surround text:
            List<IDF> ResultadosIDFST = new ArrayList();
            //Guarda las páginas con los resultados IDF:
            Map<String, List> IDFPaginasST = new HashMap();
            //Se obtiene la cantidad de documentos (lotes de ST's) del estudio:
            ND = ListaRelacionPaginas.size();

            ////////////////////////////////////////////////
            //PASO 1: Para cada termino del topico hacer:
            ////////////////////////////////////////////////
            Set conjuntoTopico = Topico.entrySet();
            Iterator it = conjuntoTopico.iterator();

            while(it.hasNext())
            {
                //Se obtiene una palabra de la consulta o topico:
                Map.Entry me = (Map.Entry)it.next();
                Termino = (String) me.getKey();

                //Se resetea el valor del IDF para el lote de ST's para cada
                //termino:
                NDti = 0;

                //Para cada extracto del Lote hacer:
                for (int i = 0; i < ListaRelacionPaginas.size(); i++)
                {
                    //Guarda el listado de terminos de cada ST:
                    List<String> ContenidoST = new ArrayList();

                    //Diccionario de terminos para los extractos ST:
                    HashSet<String> TerminosST = new HashSet<String>();

                    //Se obtienen los registros de cada fila de la tabla
                    //RELACION_PAGINA:

                    RelacionPaginas rp = new RelacionPaginas();
                    rp = ListaRelacionPaginas.get(i);

                    //Se extraen los atributos del registro:
                    id_relacion_pag = rp.getId_relacion_pagina();
                    id_pagina = rp.getId_pagina_destino();
                    pag_id_pagina = rp.getId_pagina_fuente();
                    texto_alrededor = rp.getTexto_alrededor();


                    //Se obtienen los terminos de la página:
                    if (texto_alrededor == null)
                    {
                        texto_alrededor = "null";
                    }

                    ContenidoST = cop.ObtenerPalabrasPagina(texto_alrededor, Stopwords);

                    if (ContenidoST.isEmpty() == true)
                    {
                        ContenidoST.add("null");
                    }

                    //Para cada termino se contabiliza las apariciones en el documento:
                    for (int j = 0; j < ContenidoST.size(); j++)
                    {
                        TerminosST.add(ContenidoST.get(j));
                    }

                    //Para cada termino del diccionario de la página hacer:
                    Iterator iter = TerminosST.iterator();
                    while (iter.hasNext())
                    {
                        String termino = (String) iter.next();

                        //Si el termino del tópico o de la consulta está en el diccionario
                        //de la página, entonces:
                        if (termino.compareToIgnoreCase(Termino) == 0)
                        {
                            NDti++;
                        }

                    }

                }//for paginas

                ////////////////////////////////////////////////////////////////
                //PASO 2: Se calcula el IDF del termino i de la consulta
                ////////////////////////////////////////////////////////////////

                //Se valida si NDti = 0, para que no se produzcan errores:
                if (NDti == 0){
                    NDti = 1;
                    IDF = Math.log10(ND/NDti);
                }else{
                    IDF = Math.log10(ND/NDti);
                }

                ////////////////////////////////////////////////////////////////////////
                //PASO 2: Se calcula el IDF (Okapi BM25) del termino i de la consulta
                ////////////////////////////////////////////////////////////////////////
                IDF_O = Math.log10((ND - NDti + 0.5)/(NDti + 0.5));


                ////////////////////////////////////////////////////////////////
                //PASO 3: Se guarda el IDF del termino i de la consulta
                ////////////////////////////////////////////////////////////////
                idf = new IDF();
                idf.setId_pagina(id_pagina);
                idf.setTermino(Termino);
                idf.setND(ND);
                idf.setNDti(NDti);
                idf.setIDF(IDF);
                idf.setIDF_O(IDF_O);


                //BORRAR ESTOOOOO!!!:!::!:!:!:!:!:!:!:!:!:!:!!:::!:!::!:!:!

                System.out.println("------------------------------------");
                System.out.println("id_pagina: "+ id_pagina);
                System.out.println("termino: "+ Termino);
                System.out.println("ND: "+ ND);
                System.out.println("NDti: "+ NDti);
                System.out.println("IDF: "+ IDF);
                System.out.println("IDF_O: "+ IDF_O);
                System.out.println("++++++++++++++++++++++++++++++++++++");

                //BORRAR ESTOOOOO!!!:!::!:!:!:!:!:!:!:!:!:!:!!:::!:!::!:!:!


                ResultadosIDFST.add(idf);
                IDFPaginasST.put(Termino, ResultadosIDFST);

            }//while Terminos de consulta (topico)

            return IDFPaginasST;

        }//FIN IF SURROUND TEXT

        
        return null;

    }//FIN CalcularIDF
    

    /**
     * @brief Calcula el Ni dinamico para cada página en base al avance de la muestra.
     * @param Topico, documento
     * @return double
    */
    public Map<String, Integer> CalcularNi (Map<String, Integer> Topico, String documento, Map<String,Integer> NiD)
    {
        int N = 500; //Cantidad de Documentos de la muestra. Puede cambiar.
        Map<String, Integer> terminosDoc = null;   // Terminos de la ontologia de forma < Termino, Frecuencia)
        List<String> CheakListLocal = new ArrayList();

        // Los terminos del documento vienen tokenizados en la lista
        // El documento no viene procesado( ni tokenizado ni se le efectuo stemming) solo se le sacaron los stopwords
         try{
        
            if(documento==null)
                return NiD;
            else
            if (documento.equals("") || documento.isEmpty()) {
                return NiD;
            }

            terminosDoc = new HashMap(); //Terminos de la ontologia de forma < Termino, Frecuencia)

            // Se procesa el documento de manera de extraer los terminos del documento 
            StringTokenizer tokens = new StringTokenizer(documento);
            while (tokens.hasMoreTokens()) {
                String token = tokens.nextToken();
                if (!NiD.containsKey(token)) {
                    NiD.put(token, 1);
                    CheakListLocal.add(token);
                } else {
                    if (!CheakListLocal.contains(token))
                        NiD.put(token, Integer.parseInt(NiD.get(token).toString()) + 1);
                }       
            }

        }
        catch(Exception e){
        
        }
     // En casos que el documento pese mucho, puede ocupar mucho espacio y Sobrepasar el Java Heap
        catch (OutOfMemoryError o) {
            System.err.println("Out of Memory, Java Heap Space Similitud coseno:");

        }
         
        return NiD; 
        
    }
    


}//FIN CLASE IDF ////////////////////////////////////////////////////////////////////////////////////////////////////